﻿using OpenTK;
using OpenTK.Graphics.OpenGL;
using System;
using System.Drawing;
using System.Drawing.Imaging;



namespace OpenTKConsoleTestObjLoad
{
    class Program
    {

        static void Main(string[] args)
        {
            OpenTKTestClass t = new OpenTKTestClass();
        }


        private class OpenTKTestClass
        {
            private OpenTK.GameWindow windows;
            private Texture2D texture;
            private int VBO;
            private int IBO;
            private Vertex[] vertices = new Vertex[4]
            {
                new Vertex(new Vector2(0,0), new Vector2(0,0), Color.Red),
                new Vertex(new Vector2(100,0), new Vector2(1,0), Color.Yellow),
                new Vertex(new Vector2(100,100), new Vector2(1,1), Color.Blue),
                new Vertex(new Vector2(0,100), new Vector2(0,1), Color.Green),
            };
            uint[] indices = new uint[6]
            {
                0,1,2,
                0,2,3
            };

            public OpenTKTestClass()
            {
                windows = new GameWindow(800, 600);
                windows.Load += Windows_Load;
                windows.RenderFrame += Windows_RenderFrame;

                windows.Run();
            }

            private void Windows_RenderFrame(object sender, FrameEventArgs e)
            {
                GL.ClearColor(Color.CornflowerBlue);
                GL.ClearDepth(1);
                GL.Clear(ClearBufferMask.ColorBufferBit
                    | ClearBufferMask.DepthBufferBit
                    );

                int w = windows.Width;
                int h = windows.Height;
                Matrix4 projMatrix = Matrix4.CreateOrthographicOffCenter(0, w, h, 0, 0, 1);

                GL.MatrixMode(MatrixMode.Projection);
                GL.LoadMatrix(ref projMatrix);

                GL.BindBuffer(BufferTarget.ArrayBuffer, VBO);
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, IBO);
                GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0);

                windows.SwapBuffers();
            }

            private void DrawPenguin()
            {
                GL.BindTexture(TextureTarget.Texture2D, texture.ID);

                GL.Begin(PrimitiveType.Triangles);

                GL.Color4(1f, 1f, 1f, 1f);
                //GL.Color4(1, 1, 1, 1);    //will not work
                GL.TexCoord2(0, 0); GL.Vertex2(0, 1);
                GL.TexCoord2(1, 1); GL.Vertex2(500, 525);
                GL.TexCoord2(0, 1); GL.Vertex2(0, 525);

                GL.TexCoord2(0, 0); GL.Vertex2(0, 1);
                GL.TexCoord2(1, 0); GL.Vertex2(500, 1);
                GL.TexCoord2(1, 1); GL.Vertex2(500, 525);
                GL.End();
            }

            private void Windows_Load(object sender, EventArgs e)
            {

                GL.Enable(EnableCap.Blend);
                GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

                GL.Enable(EnableCap.DepthTest);
                GL.DepthFunc(DepthFunction.Lequal);

                GL.Enable(EnableCap.Texture2D);
                GL.Enable(EnableCap.AlphaTest);
                GL.AlphaFunc(AlphaFunction.Gequal, 0.5f);

                texture = ContentPipe.LoadTexture("Content/penguin4.png");
                Console.WriteLine("OnLoad");


                VBO = GL.GenBuffer();
                GL.BindBuffer(BufferTarget.ArrayBuffer, VBO);
                GL.BufferData<Vertex>(BufferTarget.ArrayBuffer, (IntPtr)(Vertex.SizeInBytes * vertices.Length),
                    vertices, BufferUsageHint.StaticDraw);
                IBO = GL.GenBuffer();
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, IBO);
                GL.BufferData<uint>(BufferTarget.ElementArrayBuffer, (IntPtr)(sizeof(uint) * indices.Length),
                    indices, BufferUsageHint.StaticDraw);

                GL.EnableClientState(ArrayCap.VertexArray);
                GL.EnableClientState(ArrayCap.TextureCoordArray);
                GL.EnableClientState(ArrayCap.ColorArray);
                GL.EnableClientState(ArrayCap.IndexArray);

                GL.VertexPointer(2, VertexPointerType.Float, Vertex.SizeInBytes, 0);
                GL.TexCoordPointer(2, TexCoordPointerType.Float, Vertex.SizeInBytes, Vector2.SizeInBytes);
                GL.ColorPointer(4, ColorPointerType.Float, Vertex.SizeInBytes, Vector4.SizeInBytes);

            }

            private class Texture2D
            {
                private int id;
                private int width, height;
                public int ID { get { return id; } }
                public int Width { get { return width; } }
                public int Height { get { return height; } }
                public Texture2D(int id, int width, int height)
                {
                    this.id = id;
                    this.width = width;
                    this.height = height;
                }
            }


            private class ContentPipe
            {
                public static Texture2D LoadTexture(string filepath)
                {
                    Bitmap bitmap = new Bitmap(filepath);

                    int id = GL.GenTexture();
                    BitmapData bmpData = bitmap.LockBits(
                        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                        ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

                    GL.BindTexture(TextureTarget.Texture2D, id);

                    GL.TexImage2D(TextureTarget.Texture2D, 0,
                        PixelInternalFormat.Rgba,
                        bitmap.Width, bitmap.Height, 0,
                        OpenTK.Graphics.OpenGL.PixelFormat.Bgra,
                        PixelType.UnsignedByte,
                        bmpData.Scan0);

                    bitmap.UnlockBits(bmpData);

                    GL.TexParameter(TextureTarget.Texture2D,
                        TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
                    GL.TexParameter(TextureTarget.Texture2D,
                        TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);

                    return new Texture2D(id, bitmap.Width, bitmap.Height);
                }
            }

            struct Vertex
            {
                public Vector2 position;
                public Vector2 texCoord;
                public Vector4 color;

                public static int SizeInBytes { get { return Vector2.SizeInBytes * 2 + Vector4.SizeInBytes; } }

                public Color Color
                {
                    get
                    {
                        return Color.FromArgb((int)(color.W * 255), (int)(color.X * 255), (int)(color.Y * 255), (int)(color.Z * 255));
                    }
                    set
                    {
                        this.color = new Vector4(value.R / 255f, value.G / 255f, value.B / 255f, value.A / 255f);
                    }
                }

                public Vertex(Vector2 position, Vector2 texCoord, Vector4 color)
                {
                    this.position = position;
                    this.texCoord = texCoord;
                    this.color = color;
                }

                public Vertex(Vector2 position, Vector2 texCoord, Color color)
                {
                    this.position = position;
                    this.texCoord = texCoord; this.color = new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f);
                }
            }
        }
    }
}
